<!--
 * @Description: 基础弹窗
 * @Author: chenju
 * @Date: 2022-01-20 10:37:36
 * @LastEditors: qingyang
 * @LastEditTime: 2023-07-20 18:49:27
-->
<template>
  <el-dialog
    :class="customClass"
    v-model="visibleComputed"
    :close-on-click-modal="!loading"
    :close-on-press-escape="!loading"
    :show-close="!loading"
    :before-close="handleClose"
    :top="hasScroll ? localTop : '15vh'"
    v-bind="$attrs"
  >
    <template #header>
      <slot name="header"></slot>
    </template>
    <template #default>
      <el-scrollbar
        ref="scrollbarRef"
        v-bind="scrollbarAttrs"
        :wrap-style="{ minHeight: minScrollHeight }"
        v-if="hasScroll"
      >
        <slot></slot>
      </el-scrollbar>
      <slot v-else></slot>
    </template>
    <template #footer v-if="footer">
      <slot name="footer">
        <div class="dialog-footer g-flex-between-center">
          <slot name="footerLeft"><span></span></slot>
          <div>
            <el-button
              size="default"
              @click="emit('cancel')"
              v-if="showCancelButton"
              :loading="loading"
              >{{ cancelText }}</el-button
            >
            <el-button
              size="default"
              type="primary"
              @click="emit('confirm')"
              :loading="loading"
              :disabled="btnDisabled"
              >{{ confirmText }}</el-button
            >
          </div>
        </div>
      </slot>
    </template>
  </el-dialog>
</template>
<script lang="ts">
export default {
  name: 'BaseDialog'
};
</script>
<script lang="ts" setup>
import { computed, ref, withDefaults, defineProps, defineExpose, defineEmits } from 'vue';
import type { ElScrollbar } from 'element-plus';
import { useMessage } from '@/hooks/useMessage';

interface IDialogProps {
  visible: boolean;
  /**
   * 是否显示取消按钮
   * @default true
   * @type boolean
   */
  showCancelButton?: boolean;
  /**
   * 取消按钮文案
   * @default 取 消
   * @type string
   */
  cancelText?: string;
  /**
   * 确定按钮文案
   * @default 确 定
   * @type string
   */
  confirmText?: string;
  loading?: boolean;
  btnDisabled?: boolean;
  /**
   * 是否显示footer
   * @default true
   * @type
   */
  footer?: boolean;
  // 关闭前是否需要二次确认
  confirmBeforeClose?: boolean;
  /**
   * 关闭前二次确认文案
   * @default 是否确定关闭弹窗？
   * @type string
   */
  confirmBeforeCloseText?: string;
  // dialog的body是否需要内边距
  bodyNoPadding?: boolean;
  // 是否需要滚动条
  hasScroll?: boolean;
  // 滚动容器高度 必须带单位
  // hasScroll为true时，设定滚动容器高度，如果不设置则默认计算
  // 设置后会自动计算top的数值
  // 不建议与top一起使用
  scrollHeight?: string;
  // 滚动容器最大高度 必须带单位
  // hasScroll为true时，设定滚动容器高度，如果不设置则默认计算
  // 设置后会自动计算top的数值
  // 不建议与top一起使用
  // 不建议与scrollHeight一起使用
  scrollMaxHeight?: string;
  /**
   * 最小滚动高度 必须到单位
   * hasScroll为true时，设定滚动容器最小高度，默认400px
   * @default 400px
   * @type string
   */
  minScrollHeight?: string;
  /**
   * 距离顶部高度
   * @default 10vh
   * @type string
   */
  top?: string;
}
const props = withDefaults(defineProps<IDialogProps>(), {
  showCancelButton: true,
  cancelText: '取消',
  confirmText: '确定',
  footer: true,
  confirmBeforeCloseText: '是否确定关闭弹窗？',
  minScrollHeight: '400px',
  top: '15vh'
});
const emit = defineEmits(['update:visible', 'cancel', 'confirm']);
const { createConfirm } = useMessage();
const scrollbarRef = ref<InstanceType<typeof ElScrollbar>>();
const visibleComputed = computed({
  get: () => {
    return props.visible;
  },
  set: val => {
    emit('update:visible', val);
  }
});

const customClass = computed(() => {
  let classStr = 'g-dialog-wrapper';
  if (props.bodyNoPadding) {
    classStr += ' g-dialog-wrapper--no-padding';
  }
  return classStr;
});
const scrollToBottom = () => {
  const wrap: any = scrollbarRef.value?.wrapRef;
  let max = wrap?.scrollHeight - wrap?.clientHeight;
  scrollbarRef.value?.setScrollTop(max);
};
const localTop = computed(() => {
  if (props.scrollHeight) {
    return `calc((100vh - ${props.scrollHeight} - 56px - 64px) / 2)`;
  } else {
    return props.top;
  }
});

// 滚动条的属性配置
const scrollbarAttrs = computed(() => {
  const attrs = {};
  let height;
  if (props.hasScroll && props.scrollHeight) {
    height = props.scrollHeight;
  } else {
    height = `calc(100vh - ${props.top} - ${props.top} - 64px - 56px)`;
  }
  let maxHeight;
  if (props.hasScroll && props.scrollMaxHeight) {
    maxHeight = props.scrollMaxHeight;
  }

  if (maxHeight) {
    Object.assign(attrs, {
      maxHeight
    });
  } else {
    Object.assign(attrs, {
      height
    });
  }
  return attrs;
});

// 关闭前操作
const handleClose = (done: () => void) => {
  if (props.confirmBeforeClose) {
    createConfirm('提示', props.confirmBeforeCloseText, {
      iconType: 'warning'
    }).then(() => {
      done();
    });
  } else {
    done();
  }
};
defineExpose({
  scrollToBottom
});
</script>
<style></style>
